﻿/*
 * Stream.h
 *
 */
#ifndef __GDK_STREAM_H__
#define __GDK_STREAM_H__


#include <gdk/core/Types.h>
#include <gdk/core/IO.h>
#include <gdk/core/Exception.h>
#include <gdk/core/endian.h>
#include <gdk/core/Varint.h>

#include <vector>
#include <list>
#include <map>
#include <set>



namespace gdk
{




class InputStream
{
private:
	Input::Handle	_in;

private:
	__INLINE__ ssize_t available_(void) const
	{
		GDK_ASSERT(_in != NULL);

		return _in->available();
	}
	__INLINE__ ssize_t read_(void *buf, ssize_t size)
	{
		GDK_ASSERT(_in != NULL);

		return _in->read(buf, size);
	}

public:
	__INLINE__ InputStream(void)
	{
	}
	__INLINE__ InputStream(Input *in)
		: _in(in)
	{
	}
	__INLINE__ InputStream(const InputStream &in)
		: _in(in._in)
	{
	}
	__INLINE__ bool attach(Input *in)
	{
		_in = in;

		return true;
	}
	Input::Handle detach(void)
	{
		Input::Handle in = _in;

		_in = NULL;

		return in;
	}
	__INLINE__ operator Input*() const
	{
		return _in;
	}
	__INLINE__ bool isNull(void) const { return _in.isNull(); }

public:
	__INLINE__ ssize_t available(void) const
	{
		return available_();
	}
	__INLINE__ ssize_t peek(void *buf, ssize_t size) const
	{
		GDK_ASSERT(_in != NULL);

		return _in->peek(buf, size);
	}
	__INLINE__ ssize_t read(void *buf, ssize_t size)
	{
		return read_(buf, size);
	}

#define DECLARE_INPUTSTREAM_FUNCTION(Ty) \
	__INLINE__ bool read(Ty &i)\
	{\
		if (sizeof(i) != read_(&i, sizeof(i)))\
			return false;\
		i = ntoh(i);\
		return true;\
	}

	__INLINE__ bool read(wchar_t &i)
	{
		uint16_t ch;
		if (!read(ch)) return false;
		i = (wchar_t)ch;
		return true;
	}

	DECLARE_INPUTSTREAM_FUNCTION(float)
	DECLARE_INPUTSTREAM_FUNCTION(double)
	DECLARE_INPUTSTREAM_FUNCTION(bool)
	DECLARE_INPUTSTREAM_FUNCTION(char)
	DECLARE_INPUTSTREAM_FUNCTION(long)
	DECLARE_INPUTSTREAM_FUNCTION(ulong_t)
	DECLARE_INPUTSTREAM_FUNCTION(long long)
	DECLARE_INPUTSTREAM_FUNCTION(unsigned long long)
	DECLARE_INPUTSTREAM_FUNCTION(int8_t)
	DECLARE_INPUTSTREAM_FUNCTION(int16_t)
	DECLARE_INPUTSTREAM_FUNCTION(int32_t)
	//DECLARE_INPUTSTREAM_FUNCTION(int64_t)

	DECLARE_INPUTSTREAM_FUNCTION(uint8_t)
	DECLARE_INPUTSTREAM_FUNCTION(uint16_t)
	DECLARE_INPUTSTREAM_FUNCTION(uint32_t)
	//DECLARE_INPUTSTREAM_FUNCTION(uint64_t)
};

class OutputStream
{
private:
	Output::Handle	_out;


private:
	__INLINE__ ssize_t write_(const void *data, ssize_t size)
	{
		GDK_ASSERT(_out != NULL);

		return _out->write(data, size);
	}

public:
	__INLINE__ OutputStream(void)
	{
	}
	__INLINE__ OutputStream(Output *out)
		: _out(out)
	{
	}
	__INLINE__ OutputStream(const OutputStream &os)
		: _out(os._out)
	{
	}
	__INLINE__ bool attach(Output *out)
	{
		_out = out;

		return true;
	}
	Output::Handle  detach(void)
	{
		Output::Handle out = _out;

		_out = NULL;

		return out;
	}
	__INLINE__ operator Output*() const
	{
		return _out;
	}
	__INLINE__ bool isNull(void) const { return _out.isNull(); }

public:
	__INLINE__ ssize_t write(const void *buf, ssize_t size)
	{
		return write_(buf, size);
	}


#define DECLARE_OUTPUTSTREAM_FUNCTION(Ty) \
	__INLINE__ bool write(Ty i)\
	{\
		i = hton(i);\
		return sizeof(i) == write_(&i, sizeof(i));\
	}

	__INLINE__ bool write(wchar_t i)
	{
		return write((uint16_t)i);
	}

	DECLARE_OUTPUTSTREAM_FUNCTION(float)
	DECLARE_OUTPUTSTREAM_FUNCTION(double)
	DECLARE_OUTPUTSTREAM_FUNCTION(bool)
	DECLARE_OUTPUTSTREAM_FUNCTION(char)
	DECLARE_OUTPUTSTREAM_FUNCTION(long)
	DECLARE_OUTPUTSTREAM_FUNCTION(ulong_t)
	DECLARE_OUTPUTSTREAM_FUNCTION(long long)
	DECLARE_OUTPUTSTREAM_FUNCTION(unsigned long long)
	DECLARE_OUTPUTSTREAM_FUNCTION(int8_t)
	DECLARE_OUTPUTSTREAM_FUNCTION(int16_t)
	DECLARE_OUTPUTSTREAM_FUNCTION(int32_t)
	//DECLARE_OUTPUTSTREAM_FUNCTION(int64_t)

	DECLARE_OUTPUTSTREAM_FUNCTION(uint8_t)
	DECLARE_OUTPUTSTREAM_FUNCTION(uint16_t)
	DECLARE_OUTPUTSTREAM_FUNCTION(uint32_t)
	//DECLARE_OUTPUTSTREAM_FUNCTION(uint64_t)

};


#define DECLARE_SERIALIZE(Ty) \
	__INLINE__ gdk::InputStream& operator >>(gdk::InputStream &is, Ty &i) __THROW1\
	{\
		if (!is.read(i))\
			__THROW__(__TEXT__("gdk::InputStream& operator >>(gdk::InputStream &is,") __TEXT__(#Ty) __TEXT__(" &i)"));\
		return is;\
	}\
	__INLINE__ gdk::OutputStream& operator <<(gdk::OutputStream &os, const Ty &i) __THROW1\
	{\
		if (!os.write(i))\
			__THROW__(__TEXT__("gdk::OutputStream& operator <<(gdk::OutputStream &os, const ") __TEXT__(#Ty) __TEXT__(" &i)"));\
		return os;\
	}

DECLARE_SERIALIZE(wchar_t)
DECLARE_SERIALIZE(float)
DECLARE_SERIALIZE(double)
DECLARE_SERIALIZE(bool)
DECLARE_SERIALIZE(char)
DECLARE_SERIALIZE(long)
DECLARE_SERIALIZE(ulong_t)
DECLARE_SERIALIZE(long long)
DECLARE_SERIALIZE(unsigned long long)
DECLARE_SERIALIZE(int8_t)
DECLARE_SERIALIZE(int16_t)
DECLARE_SERIALIZE(int32_t)
//DECLARE_SERIALIZE(int64_t)
DECLARE_SERIALIZE(uint8_t)
DECLARE_SERIALIZE(uint16_t)
DECLARE_SERIALIZE(uint32_t)
//DECLARE_SERIALIZE(uint64_t)


template GDK_CORE_EXPORT InputStream& operator >><InputStream>(InputStream &is, Varint &o) __THROW1;
template GDK_CORE_EXPORT OutputStream& operator <<<OutputStream>(OutputStream &os, const Varint &o) __THROW1;
template GDK_CORE_EXPORT InputStream& operator >><InputStream>(InputStream &is, Varint64 &o) __THROW1;
template GDK_CORE_EXPORT OutputStream& operator <<<OutputStream>(OutputStream &os, const Varint64 &o) __THROW1;

GDK_CORE_EXPORT OutputStream& operator <<(OutputStream &os, InputStream &is) __THROW1;
__INLINE__ InputStream& operator >>(InputStream &is, OutputStream &os) __THROW1
{
	os << is;
	return is;
}


template GDK_CORE_EXPORT InputStream& operator >><InputStream>(InputStream &is, StringAnsi &str) __THROW1;
template GDK_CORE_EXPORT InputStream& operator >><InputStream>(InputStream &is, StringWide &str) __THROW1;
template GDK_CORE_EXPORT InputStream& operator >><InputStream>(InputStream &is, StringUtf8 &str) __THROW1;

template GDK_CORE_EXPORT OutputStream& operator <<<OutputStream>(OutputStream &os, const StringAnsi &str) __THROW1;
template GDK_CORE_EXPORT OutputStream& operator <<<OutputStream>(OutputStream &os, const StringWide &str) __THROW1;
template GDK_CORE_EXPORT OutputStream& operator <<<OutputStream>(OutputStream &os, const StringUtf8 &str) __THROW1;




template<typename TyIs>
TyIs& operator >>(TyIs &is, std::vector<bool> &o) __THROW1
{
	typedef typename std::vector<bool>::size_type size_type;

	Varint count;
	is >> count;
	if (static_cast<size_type>(count) > o.max_size())
		__THROW__(__TEXT__("std::vector too long."));
	if (is.available() < count)
		__THROW__(__TEXT__("std::vector invalid size."));

	o.resize(count);
	for (ssize_t i = 0; i < count; ++i)
	{
		bool v;
		is >> v;
		o[i] = v;
	}
	return is;
}
template<typename TyIs, typename TyVal>
TyIs& operator >>(TyIs &is, std::vector<TyVal> &o) __THROW1
{
	typedef typename std::vector<TyVal>::size_type size_type;

	Varint count;
	is >> count;
	if (static_cast<size_type>(count) > o.max_size())
		__THROW__(__TEXT__("std::vector too long."));
	if (is.available() < count)
		__THROW__(__TEXT__("std::vector invalid size."));

	o.resize(count);
	for (ssize_t i = 0; i < count; ++i)
	{
		/*
		TyVal v;
		is >> v;
		o[i] = v;
		*/
		is >> (TyVal&)(o[i]);
	}
	return is;
}
template<typename TyOs, typename TyVal>
TyOs& operator <<(TyOs &os, std::vector<TyVal> const &o) __THROW1
{
	if (o.size() > SSIZE_MAX)
		__THROW__(__TEXT__("std::vector too long."));

	Varint count = static_cast<ssize_t>(o.size());
	os << count;
	for (ssize_t i = 0; i < count; ++i)
	{
		os << o[i];
	}
	return os;
}


template<typename TyIs, typename TyVal>
TyIs& operator >>(TyIs &is, std::list<TyVal> &o) __THROW1
{
	typedef typename std::list<TyVal>::size_type size_type;
	typedef typename std::list<TyVal>::iterator  iterator;

	Varint count;
	is >> count;
	if (static_cast<size_type>(count) > o.max_size())
		__THROW__(__TEXT__("std::list too long."));
	if (is.available() < count)
		__THROW__(__TEXT__("std::list invalid size."));

	if (o.size() > 0) o.clear();
	while (count-- > 0)
	{
		/*
		TyVal val;
		is >> val;

		o.insert(o.end(), val);
		*/
		iterator it = o.insert(o.end(), TyVal());
		is >> (TyVal&)(*it);
	}
	return is;
}
template<typename TyOs, typename TyVal>
TyOs& operator <<(TyOs &os, std::list<TyVal> const &o) __THROW1
{
	typedef typename std::list<TyVal>::const_iterator const_iterator;

	if (o.size() > SSIZE_MAX)
		__THROW__(__TEXT__("std::list too long."));

	Varint count = static_cast<ssize_t>(o.size());
	os << count;
	for (const_iterator it = o.begin(); it != o.end(); ++it)
	{
		os << *it;
	}
	return os;
}


template<typename TyIs, typename TyKey, typename TyVal>
TyIs& operator >>(TyIs &is, std::map<TyKey, TyVal> &o) __THROW1
{
	typedef typename std::map<TyKey, TyVal>::size_type size_type;

	Varint count;
	is >> count;
	if (static_cast<size_type>(count) > o.max_size())
		__THROW__(__TEXT__("std::map too long."));
	if (is.available() < count)
		__THROW__(__TEXT__("std::map invalid size."));

	if (o.size() > 0) o.clear();
	while (count-- > 0)
	{
		/*
		TyKey key;
		TyVal val;
		is >> key >> val;
		o[key] = val;
		*/
		TyKey key;
		is >> key;
		is >> (TyVal&)(o[key]);
	}
	return is;
}
template<typename TyOs, typename TyKey, typename TyVal>
TyOs& operator <<(TyOs &os, std::map<TyKey, TyVal> const &o) __THROW1
{
	typedef typename std::map<TyKey, TyVal>::const_iterator const_iterator;

	if (o.size() > SSIZE_MAX)
		__THROW__(__TEXT__("std::map::size too larger"));

	Varint count = static_cast<ssize_t>(o.size());
	os << count;
	for (const_iterator it = o.begin(); it != o.end(); ++it)
	{
		os << it->first
			<< it->second;
	}
	return os;
}


template<typename TyIs, typename TyVal>
TyIs& operator >>(TyIs &is, std::set<TyVal> &o) __THROW1
{
	typedef typename std::set<TyVal>::size_type size_type;

	Varint count;
	is >> count;
	if (static_cast<size_type>(count) > o.max_size())
		__THROW__(__TEXT__("std::set too long."));
	if (is.available() < count)
		__THROW__(__TEXT__("std::set invalid size."));

	if (o.size() > 0) o.clear();
	while (count-- > 0)
	{
		TyVal val;
		is >> val;
		o.insert(val);
	}
	return is;
}
template<typename TyOs, typename TyVal>
TyOs& operator <<(TyOs &os, std::set<TyVal> const &o) __THROW1
{
	typedef typename std::set<TyVal>::const_iterator const_iterator;

	if (o.size() > SSIZE_MAX)
		__THROW__(__TEXT__("std::set::size too larger"));

	Varint count = static_cast<ssize_t>(o.size());
	os << count;
	for (const_iterator it = o.begin(); it != o.end(); ++it)
	{
		os << *it;
	}
	return os;
}





}//namespace gdk



#endif /*__GDK_STREAM_H__*/
